<template>
  <view>
    <view
      class="flex flex-col flex-col-top-start flex-between relative overflow"
      :style="[
        {
          width: _containerWidth + 'rpx',
          height: _containerHeight.maxHeight + 50 + 'px',
        },
      ]"
    >
      <slot></slot>
    </view>
    <!-- 虚拟加载占位符。 -->
    <tm-sheet
      v-if="_totalNum.length != _list.length"
      _class="flex flex-center"
      :margin="[0, 0]"
      :padding="[0, 0]"
    >
      <tm-icon name="tmicon-shuaxin" spin></tm-icon>
    </tm-sheet>
  </view>
</template>

<script lang="ts" setup>
/**
 * 瀑布流
 * @description 瀑布流,只能放置tm-waterfall-item组件不可放置其它组件。
 * @example <tm-waterfall><tm-waterfall-item ></tm-waterfall-item></tm-waterfall>
 */
import { computed, nextTick, provide, Ref, ref, watch } from "vue";
import tmSheet from "../tm-sheet/tm-sheet.vue";
import tmIcon from "../tm-icon/tm-icon.vue";
import { itemParenSG } from "./interface";
const props = defineProps({
  /**组件整体宽度 */
  width: {
    type: Number,
    default: 750,
  },
  /**元素间的间距 */
  gutter: {
    type: Number,
    default: 12,
  },
});

//容器的宽度
const _containerWidth = computed(() => props.width);
//项目的宽度
const _itemRealWidth = computed(() => {
  return (_containerWidth.value - props.gutter) / 2;
});
//组件标识
const parentNameId = "tmWaterfallId";
//这是首次进行缓存的数据。后续列表如果更新，针对id进行队列更新。
const _cacheList: Ref<Array<itemParenSG>> = ref([]);
//这是按队列排序的左右数据主要是用来计算最大高度的。
const _totalSort: Ref<Array<Array<itemParenSG>>> = ref([[], []]);
//排序的一列表数据
const _list: Ref<Array<itemParenSG>> = ref([]);
const _totalNum: Ref<Array<number>> = ref([]);
// //当前列表的高度,这是第一次的缓存高度。
//当前列表的排序后的列表高度

const _containerHeight = computed(() => {
  let gu = uni.upx2px(props.gutter);
  let lh = _totalSort.value[0].map((el) => el.height);
  let l_height = lh.length == 0 ? 0 : lh.reduce((a, b) => a + b + gu);
  let rh = _totalSort.value[1].map((el) => el.height);
  let r_height = rh.length == 0 ? 0 : rh.reduce((a, b) => a + b + gu);
  return {
    left: l_height,
    right: r_height,
    maxHeight: Math.max(r_height, l_height),
    minHeight: Math.min(r_height, l_height),
  };
});

provide(
  "tmWaterFallItemRealWidth",
  computed(() => uni.upx2px(_itemRealWidth.value))
);
function sumTotal(id: number) {
  _totalNum.value.push(id);
}
async function pushKey(n: itemParenSG) {
  let index = _cacheList.value.findIndex((el) => el.id == n.id);
  let item = n;
  if (index > -1) {
    //已存在的不在更新高度，只作更新数据。
    _cacheList.value[index] = item;
    return item;
  } else {
    _cacheList.value.push(item);
    return countPushSort(item);
  }
}
function clear() {
  _cacheList.value = [];
  _list.value = [];
  _totalNum.value = [];
  _totalSort.value = [[], []];
}

//排序数据。
function countPushSort(item: itemParenSG) {
  //当前数据是
  let dir = _containerHeight.value.left > _containerHeight.value.right ? 1 : 0;
  let bottom = _totalSort.value[dir][_totalSort.value[dir].length - 1]?.bottom ?? 0;
  item.top = bottom + uni.upx2px(props.gutter);
  item.bottom = item.top + item.height;
  item.left = dir == 0 ? 0 : uni.upx2px(_itemRealWidth.value) + uni.upx2px(props.gutter);
  let index = _list.value.findIndex((el) => el.id == item.id);
  _totalSort.value[dir].push(item);
  if (index > -1) {
    _list.value[index] = item;
  } else {
    _list.value.push(item);
  }
  return item;
}

defineExpose({ parentNameId: parentNameId, pushKey, sumTotal, clear });
</script>
